#include <Arduino.h>
#include <SPI.h>

#include "esp32-hal-timer.h"  
#include "movement.h"
#include "planner.h"

#define DAC_HOST HSPI_HOST
#define MPIN_NUM_MISO 12
#define MPIN_NUM_MOSI 13
#define MPIN_NUM_CLK 14
#define MPIN_NUM_CS 15

#define PIN_LASER_PWM 16


SemaphoreHandle_t IsMoving = NULL;
SemaphoreHandle_t TimeStampTest = NULL;

esp_timer_handle_t ExecuteTimerHandle = NULL;

spi_device_handle_t spi;

esp_err_t ret;
spi_transaction_t t;


#define TIMER_FREQUENCY_HZ 1000
// 声明一个硬件定时器指针
hw_timer_t *ptimer = NULL;
// 用于在中断中处理多核共享资源时的临界区保护


static bool XYMove(void);

static void WriteDAC8552(uint16_t xVal, uint16_t yVal);
static void spisend(uint32_t data);



int *TimestoExec, *NeedLasertoSend;
uint16_t *pXDAValtoSend, *pYDAValtoSend;
// 计数器
static int ExecTimesCount;

void IRAM_ATTR kong()
{

    if (ExecTimesCount != *TimestoExec)
    {
        // ESP_LOGI("XYMOVE", "before SPIWRITE");
        WriteDAC8552(pXDAValtoSend[ExecTimesCount], pYDAValtoSend[ExecTimesCount]);
        ExecTimesCount++;
    }
    else
    {

        // esp_timer_stop(ExecuteTimerHandle);
        timerStop(ptimer);

        // 释放信号量
        xSemaphoreGive(IsMoving);
    }
    // portEXIT_CRITICAL_ISR(&timerMux);
}

void MovInit(void)
{
   
  // 配置CS引脚
  pinMode(MPIN_NUM_CS, OUTPUT);
  digitalWrite(MPIN_NUM_CS, HIGH);

  // 启动默认SPI
    //   SPI.begin(); 
  SPI.begin(MPIN_NUM_CLK, MPIN_NUM_MISO, MPIN_NUM_MOSI, MPIN_NUM_CS);


    // SPI output motor init val
    uint32_t sd = 0x010038;
    spisend(sd);
    WriteDAC8552(32767, 32767);

    ptimer = timerBegin(TIMER_FREQUENCY_HZ); 

    timerAttachInterrupt(ptimer, &kong);
    // -----------------------------esp软件定时

    // esp_timer_create_args_t timer_args = {
    //     .callback = kong,
    //     .arg = (void *)0,
    //     // .dispatch_method = ESP_TIMER_ISR,
    //     .dispatch_method = ESP_TIMER_TASK,
        
    //     .name = "DAValProcessTimer",
    //     .skip_unhandled_events = false,
    // };
    // esp_timer_create(&timer_args, &ExecuteTimerHandle);

    // ledc_timer_config_t ledc_timer = {
    //     .duty_resolution = LEDC_TIMER_10_BIT, // PWM占空比分辨率
    //     .freq_hz = 5000,                      // PWM信号频率
    //     .speed_mode = LEDC_HIGH_SPEED_MODE,   // 定时器模式
    //     .timer_num = LEDC_TIMER_0             // 定时器序号;使用哪个定时器0-3;
    // };
    // // 配置定时器0的高速通道
    // ledc_timer_config(&ledc_timer);

    // ledc_channel_config_t ledc_channel = {
    //     .channel = LEDC_CHANNEL_7, // LED控制器通道号,
    //     .duty = 0,
    //     .gpio_num = 16,                     // LED控制器通道对应GPIO,
    //     .speed_mode = LEDC_HIGH_SPEED_MODE, // 模式,
    //     .timer_sel = LEDC_TIMER_0,          // 使用哪个定时器0-3
    // };
    // // 配置LED控制器
    // ledc_channel_config(&ledc_channel);

    // *********************** SEMAPHORE **************************************
    IsMoving = xSemaphoreCreateBinary();
    xSemaphoreGive(IsMoving);
}

static void spisend(uint32_t data)
{
    // 若你的 DAC 是 SPI mode 1, 8MHz
    SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE1));
    digitalWrite(MPIN_NUM_CS, LOW);

    // 发送高8位
    SPI.transfer((data >> 16) & 0xFF);
    // 发送中8位
    SPI.transfer((data >> 8) & 0xFF);
    // 发送低8位
    SPI.transfer(data & 0xFF);

    digitalWrite(MPIN_NUM_CS, HIGH);
    SPI.endTransaction();
}

uint32_t spivesselx = 0x00, spivessely = 0x01; // DAC8563
static void WriteDAC8552(uint16_t xVal, uint16_t yVal)
{
    uint8_t xValHighByte = xVal >> 8;
    uint8_t yValHighByte = yVal >> 8;

    spivesselx &= (uint32_t)0xFF;
    spivessely &= (uint32_t)0xFF;

    spivesselx |= (uint32_t)xVal << 16;
    spivesselx |= (uint32_t)xValHighByte << 8;
    spivessely |= (uint32_t)yVal << 16;
    spivessely |= (uint32_t)yValHighByte << 8;

    spisend(spivesselx);
    spisend(spivessely);
}



void XYStartMove(void)
{
    ExecTimesCount = 0;

    xQueueReceive(XPlannerDAValQueueHandle, &pXDAValtoSend, portMAX_DELAY);
    xQueueReceive(YPlannerDAValQueueHandle, &pYDAValtoSend, portMAX_DELAY);
    xQueueReceive(TimesInterpolationQueueHandle, &TimestoExec, portMAX_DELAY);

    timerStart(ptimer); //启动定时中断
}
